package com.gomoku.service;

import com.gomoku.model.Board;
import com.gomoku.model.Move;
import com.gomoku.utils.BoardEvaluator;
import com.gomoku.utils.Scores;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.gomoku.model.Board.AI;
import static com.gomoku.model.Board.PLAYER;

@Service
public class AIService {

    private static int MAX_DEPTH = 4;
    private static final int AI_LIMITED_MOVE_NUM = 15;  // AI 限制的最大节点数量
    private BoardEvaluator boardEvaluator;

    public static void setMaxDepth(int difficult){
        MAX_DEPTH = difficult;
    }

    public Move calculateNextMove(Board board) {
        return minimax(board,MAX_DEPTH, Integer.MIN_VALUE, Integer.MAX_VALUE, true);
    }

    private Move minimax(Board board, int depth, int alpha, int beta, boolean isMax) {
        Move bestMove = null;
        int self  = isMax ? AI : PLAYER;
        int rival = isMax? PLAYER : AI;
        if (depth == 0 ) { // 到达最大深度或游戏结束
            //计算self的分数值-rival的分数值
            int score = boardEvaluator.evaluate(board, self,rival, true);
            if(self == AI){  //如果当前是AI，那么就返回分数（selfScore - rivalScore）
                return new Move(-1, -1, score);
            }
            else{  //如果当前是玩家，那么就返回分数 -(rivalScore - selfScore)
                return new Move(-1, -1, -score);
            }
        }

        List<Move> availableMoves = generateMoves(board, self);
        if (availableMoves.isEmpty()) { // 无可行移动
            //这里的score = selfScore - rivalScore
            int score = boardEvaluator.evaluate(board, self,rival, true);
            if(self == AI){  //如果当前是AI，那么就返回分数（selfScore - rivalScore）
                return new Move(-1, -1, score);
            }
            else{  //如果当前是玩家，那么就返回分数 -(rivalScore - selfScore)
                return new Move(-1, -1, -score);
            }
        }

        if (isMax) { // Maximizer 回合
            int maxEval = Integer.MIN_VALUE;
            for (Move move : availableMoves) {
                board.makeMove(move.getRow(), move.getCol(), true); // AI 移动

                if (board.checkWin(move.getRow(), move.getCol())) {
                    board.undoMove(move.getRow(), move.getCol()); // 恢复状态
                    return new Move(move.getRow(), move.getCol(), Scores.WIN_SCORE); // AI 胜利
                }

                int eval = minimax(board,depth - 1, alpha, beta, false).getScore();
                if (eval > maxEval) {
                    maxEval = eval;
                    bestMove = new Move(move.getRow(), move.getCol(), eval);
                }

                board.undoMove(move.getRow(), move.getCol()); // 恢复状态
                alpha = Math.max(alpha, eval);
                if (alpha >= beta) break; // Alpha-Beta 剪枝
            }
        } else { // Minimizer 回合
            int minEval = Integer.MAX_VALUE;
            for (Move move : availableMoves) {
                board.makeMove(move.getRow(), move.getCol(), false); // 玩家移动

                if (board.checkWin(move.getRow(), move.getCol())) {
                    board.undoMove(move.getRow(), move.getCol()); // 恢复状态
                    return new Move(move.getRow(), move.getCol(), -Scores.WIN_SCORE); // 玩家胜利
                }

                int eval = minimax(board,depth - 1, alpha, beta, true).getScore();
                if (eval < minEval) {
                    minEval = eval;
                    bestMove = new Move(move.getRow(), move.getCol(), eval);
                }

                board.undoMove(move.getRow(), move.getCol()); // 恢复状态
                beta = Math.min(beta, eval);
                if (alpha >= beta) break; // Alpha-Beta 剪枝
            }
        }

        return bestMove != null ? bestMove : new Move(-1, -1, isMax ? Integer.MIN_VALUE : Integer.MAX_VALUE);
    }



    //返回对自己(turn)有利的moves
    //这些moves按照有利程度从大到小进行排序
    private List<Move> generateMoves(Board board,int turn) {
        boardEvaluator = new BoardEvaluator();
        int selfPoint = (turn == AI ? AI: PLAYER);
        int rivalPoint = (turn == AI? PLAYER: AI);
        List<Move> fives = new ArrayList<Move>();  //可以形成五连的点。
        List<Move> selfFours = new ArrayList<Move>();  //己方的活四。
        List<Move> rivalFours = new ArrayList<Move>();  //对方的活四。

        List<Move> moves = new ArrayList<Move>();
        int[][] grid = board.getGrid();
        for (int row = 0; row < Board.BOARD_SIZE; row++) {
            for (int col = 0; col < Board.BOARD_SIZE; col++) {
                if (grid[row][col] == 0 && hasNeighbor(grid, row, col, 1)) {
                    // 评估点的分数
                    int[] scores = boardEvaluator.evaluatePointScore(grid,row, col, selfPoint, rivalPoint);
                    int selfScore = scores[0];
                    int rivalScore = scores[1];
                    Move move = new Move(row, col, Math.max(selfScore,rivalScore));

                    // 根据分数分类
                    if (selfScore >= Scores.FIVE || rivalScore >= Scores.FIVE) {
                        fives.add(move);
                    } else if (selfScore >= Scores.LIVE_FOUR) {
                        selfFours.add(move);
                    } else if (rivalScore >= Scores.LIVE_FOUR) {
                        rivalFours.add(move);
                    }
                    moves.add(move);
                }
            }
        }
        // 如果存在直接获胜或阻挡获胜的位置，优先返回
        if (!fives.isEmpty()) return fives;
        // 如果对手有威胁，则优先处理
        if (!rivalFours.isEmpty()) {
            return rivalFours;
        }
        if (!selfFours.isEmpty()) return selfFours;

        moves.sort((a, b) -> b.getScore() - a.getScore());
        // 如果深度较高且可能节点较多，则限制节点数量
        if (MAX_DEPTH > 3 && moves.size() > AI_LIMITED_MOVE_NUM) {
            return moves.subList(0, AI_LIMITED_MOVE_NUM);
        }
        return moves;
    }

    private boolean hasNeighbor(int[][] grid, int row, int col,int radius ) {
        int rl = row - radius;
        int rr = row + radius;
        int cl = col - radius;
        int cr = col + radius;
        for (int i = Math.max(0, rl); i <= Math.min(Board.BOARD_SIZE - 1, rr); i++) {
            for (int j = Math.max(0, cl); j <= Math.min(Board.BOARD_SIZE - 1, cr); j++) {
                if (grid[i][j] != 0) {
                    return true;
                }
            }
        }
        return false;
    }

}